
<template>
  <canvas 
    ref="canvasRef" 
    @click="handleCanvasClick"
    @wheel="handleCanvasWheel"
    @mousemove="handleCanvasMouseMove"
    @mousedown="startDrag"
    @mouseup="endDrag"
    @mouseleave="endDrag"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
    width="1200" 
    height="800"
  ></canvas>
  <label for="slider">选择一个值：</label>
  <input type="range" id="slider" name="slider" min="0" max="100" value="50" v-model="sliderValue" @change="handleSliderChange">
</template>

<script setup lang="ts">
    import { ref, onMounted, reactive } from 'vue';

    import guilinMapGeoJSON from './assets/guilin.geo.json';

    const guilinGeoJSON = ref(guilinMapGeoJSON);
    console.log("@", guilinGeoJSON.value);
    console.log("@@", guilinGeoJSON.value.type)
    console.log("@@", guilinGeoJSON.value.features)
    console.log("@@@", guilinGeoJSON.value.features[0])

    let scale = 1;
    let canvasW = 1200//window.innerWidth
    let canvasH = 800//window.innerHeight
    let geoCenterX = 0, geoCenterY = 0  // 地图区域的经纬度中心点
    let offsetX = 0, offsetY = 0    // 鼠标事件的位置信息
    let eventType =''
    let areaName :string[] = []
    let lastAreaIndex = 0

    let isDragging = ref(false);
    let dragStartX = ref(0);
    let dragStartY = ref(0);

    let screenOffsetX = 0, screenOffsetY = 0 // 拖拽偏移

    let touchStartDistance = 0

    let sliderValue = ref(50)

    type CountyFeature = {
        path: Path2D;
        color: string;
        centroid: [number, number];
    };

    const canvasRef = ref<HTMLCanvasElement | null>(null);
    const counties = ref<CountyFeature[]>([]);

    
   function handleSliderChange(event: any) {
        sliderValue.value = event.target.value
        scale = scale + (sliderValue.value - 50) * 2
        console.log("sliderValue:", sliderValue.value, "scale:", scale)
        initMap()
    }
    

// 初始化绘制
    const initMap = () => {
        if (!canvasRef.value) return;
        const ctx = canvasRef.value.getContext('2d');
        // console.log("ctx", ctx)

        if (!ctx) 
            return;

        ctx.clearRect(0, 0, 1200, 800);
        const width = 1200;
        const height = 800;

        // getBoxArea()
        drawArea(ctx)
        drawText(ctx)

     
    };

    // 获取包围盒范围，计算包围盒中心经纬度坐标，计算地图缩放系数
    function getBoxArea() {
        let N = -90, S = 90, W = 180, E = -180
        guilinGeoJSON.value.features.forEach(item => {
            // 将MultiPolygon和Polygon格式的地图处理成统一数据格式
            // if (item.geometry.type === 'Polygon') {
            //     item.geometry.coordinates = item.geometry.coordinates
            // }
            // 取四个方向的极值
            item.geometry.coordinates.forEach(area => {
                let areaN = - 90, areaS = 90, areaW = 180, areaE = -180
                //console.log("area", area)
                area.forEach(elem => {
                    if (elem[0] < W) {
                        W = elem[0]
                    }
                    if (elem[0] > E) {
                        E = elem[0]
                    }
                    if (elem[1] > N) {
                        N = elem[1]
                    }
                    if (elem[1] < S) {
                        S = elem[1]
                    }
                })
            })
        })
        // 计算包围盒的宽高
        let width = Math.abs(E - W)
        let height = Math.abs(N - S)
        let wScale = canvasW / width
        let hScale = canvasH / height
        // 计算地图缩放系数
        scale = wScale > hScale ? hScale : wScale
        // 获取包围盒中心经纬度坐标
        geoCenterX = (E + W) / 2
        geoCenterY = (N + S) / 2
    }

    // 将经纬度坐标转换为屏幕坐标
    function toScreenPosition(horizontal:number, vertical:number) {
        return {
            x: (horizontal - geoCenterX) * scale,
            //地理坐标从下向上增加，屏幕坐标从上向下增加
            y: (geoCenterY - vertical) * scale
        }
    }

    // 绘制地图各子区域
    function drawArea(ctx:CanvasRenderingContext2D) {
        let dataArr = guilinGeoJSON.value.features
        let cursorFlag = false
        // if (!canvasRef.value) return;
        // const ctx = canvasRef.value.getContext('2d');
        // if (!ctx) return;

        for (let i = 0; i < dataArr.length; i++) {
            let centerX = canvasW / 2
            let centerY = canvasH / 2
            dataArr[i].geometry.coordinates.forEach(area => {
                ctx.save()
                ctx.beginPath()
                ctx.translate(centerX + screenOffsetX, centerY + screenOffsetY)
                area.forEach((elem, index) => {
                    let position = toScreenPosition(elem[0], elem[1])
                    if (index === 0) {
                        ctx.moveTo(position.x, position.y)
                    } else {
                        ctx.lineTo(position.x, position.y)
                    }
                })
                ctx.closePath()
                ctx.strokeStyle = '#00cccc'
                ctx.lineWidth = 1
                // 将鼠标悬浮的区域设置为橘黄色
                if (ctx.isPointInPath(offsetX, offsetY)) {
                    cursorFlag = true
                    //if(lastAreaIndex!== i){
                        ctx.fillStyle = 'orange'
                        // console.log("lastAreaIndex:", lastAreaIndex, "color orange")
                    //}

                    if (eventType === 'click' || lastAreaIndex === i) {
                        lastAreaIndex = i
                        console.log(areaName[i])
                        ctx.fillStyle = 'red'

                    }
                } else {
                    ctx.fillStyle = '#004444'
                    // console.log("not isPointInPath");
                }
                ctx.fill()
                ctx.stroke()
                ctx.restore()
            });
            // 动态设置鼠标样式
            // if (cursorFlag) {
            //     canvas.style.cursor = 'pointer'
            // } else {
            //     canvas.style.cursor = 'default'
            // }
        }
    }

    // 标注地图上的城市名称
    function drawText(ctx:CanvasRenderingContext2D) {
        let centerX = canvasW / 2
        let centerY = canvasH / 2
        guilinGeoJSON.value.features.forEach(item => {
            ctx.save()
            ctx.beginPath()
            ctx.translate(centerX + screenOffsetX, centerY + screenOffsetY) // 将画笔移至画布的中心
            ctx.fillStyle = '#fff'
            ctx.font = '12px Microsoft YaHei'
            ctx.textAlign = 'center'
            ctx.textBaseline = 'middle'
            let x = 0, y = 0
            //  因不同的geojson文件中中心点属性信息不同，这里需要做兼容性处理
            // if (item.properties.cp) {
            //     x = item.properties.cp[0]
            //     y = item.properties.cp[1]
            // } else if (item.properties.centroid) {
            //     x = item.properties.centroid[0]
            //     y = item.properties.centroid[1]
            // } else if (item.properties.center) {
            //     x = item.properties.center[0]
            //     y = item.properties.center[1]
            // }
            x = item.properties.center[0]
            y = item.properties.center[1]
            let position = toScreenPosition(x, y)
            ctx.fillText(item.properties.name, position.x, position.y);
            ctx.restore()
        })
    }

    // 点击处理
    function handleCanvasClick(event: MouseEvent){
        offsetX = event.offsetX
        offsetY = event.offsetY
        eventType = 'click'
        initMap()
    };

    function handleCanvasWheel(event: WheelEvent) {
        console.log("handleCanvasWheel!!!")
        if (event.deltaY > 0) { //向下滑动 缩小
            if (scale > 10) {
                scale -= 10
                console.log("handleCanvasWheel!!! scale-=10")
            }
        } else { //向上滑动 放大
            scale += 10
            console.log("handleCanvasWheel!!! scale+=10")
        }
        console.log("handleCanvasWheel!!! scale:", scale)
        eventType = 'mousewheel'
        initMap()
    }

    function handleCanvasMouseMove(event: MouseEvent) {
        offsetX = event.offsetX
        offsetY = event.offsetY
        eventType = 'mousemove'

        if(isDragging.value){
            //拖拽的坐标偏移
            screenOffsetX = event.clientX - dragStartX.value
            screenOffsetY = event.clientY - dragStartY.value
            console.log("screenOffsetX:", screenOffsetX, "screenOffsetY:", screenOffsetY)
            //移动画布
            // canvasRef.value.style.transform = `translate(${screenOffsetX}px, ${screenOffsetY}px)`
        }        

        initMap()
    }

    const startDrag = (event: MouseEvent) => {
        if (canvasRef.value) {
            isDragging.value = true;
            dragStartX.value = event.clientX;
            dragStartY.value = event.clientY;
        }
    };

    const endDrag = () => {
        isDragging.value = false;
    };
 
    function calculateDistance(touches: TouchList)
    {
        const x1 = touches[0].clientX
        const y1 = touches[0].clientY
        const x2 = touches[1].clientX
        const y2 = touches[1].clientY
        return Math.sqrt((x2-x1)**2 + (y2-y1)**2)
    }

    function handleTouchStart(event:TouchEvent)
    {
        if(event.touches.length === 2)
        {
            touchStartDistance = calculateDistance(event.touches)
        }
        else if(event.touches.length === 1)
        {
            isDragging.value = true;
            dragStartX.value = event.touches[0].clientX;
            dragStartY.value = event.touches[0].clientY;
        }
    }

    function handleTouchMove(event: TouchEvent)
    {
        if(event.touches.length === 2)
        {
            const currentDistance = calculateDistance(event.touches)
            const detalDistance = currentDistance - touchStartDistance

            const zoomFactor = 1.05
            if(detalDistance > 0){
                scale *= zoomFactor
            }
            else if(detalDistance < 0){
                scale /= zoomFactor
            }

            // if (!canvasRef.value) 
            //     return;
            // const ctx = canvasRef.value.getContext('2d');
            // // console.log("ctx", ctx)

            // if (!ctx) 
            //     return;
            // ctx.setTransform(scale, 0, 0, scale, 0, 0)
            touchStartDistance = currentDistance


        }
        else if(event.touches.length === 1)
        {
            offsetX = event.touches[0].clientX
            offsetY = event.touches[0].clientY
            eventType = 'mousemove'

            if(isDragging.value){
                //拖拽的坐标偏移
                screenOffsetX = event.touches[0].clientX - dragStartX.value
                screenOffsetY = event.touches[0].clientY - dragStartY.value
                console.log("screenOffsetX:", screenOffsetX, "screenOffsetY:", screenOffsetY)
                //移动画布
                // canvasRef.value.style.transform = `translate(${screenOffsetX}px, ${screenOffsetY}px)`
            }        

            initMap()
        }
    }

    const handleTouchEnd = (event: TouchEvent) => {};


    function initAreaNmae() {

        guilinGeoJSON.value.features.forEach(item => {
            areaName.push(item.properties.name)
        })
    }

    onMounted(() => {
        initAreaNmae()
        getBoxArea()
        initMap();
    });

</script>

<style scoped>
    canvas {
        border: 1px solid #eee;
        background: #f5f5f5;
        margin: 20px;
    }
</style>
